from io import StringIO

from django.conf import settings
from django.contrib.sites.models import Site
from django.core.management import call_command
from django.core.management.base import CommandError
from django.test import TestCase
from django.test.utils import override_settings

from unittest.mock import patch


class SetDefaultSiteTests(TestCase):
    """Tests for set_default_site command."""

    @override_settings(SITE_ID=321)
    def test_should_raise_CommandError_when_Site_object_does_not_exist(self):
        with self.assertRaisesRegex(
            CommandError, "Default site with pk=321 does not exist"
        ):
            call_command("set_default_site")

    @patch("django_extensions.management.commands.set_default_site.socket")
    def test_should_raise_CommandError_if_system_fqdn_return_None(self, m_socket):
        m_socket.getfqdn.return_value = None
        with self.assertRaisesRegex(CommandError, "Cannot find systems FQDN"):
            call_command("set_default_site", "--system-fqdn")

    def test_should_raise_CommandError_if_both_domain_and_set_as_system_fqdn_are_present(
        self,
    ):
        with self.assertRaisesRegex(
            CommandError, "The set_as_system_fqdn cannot be used with domain option."
        ):
            call_command("set_default_site", "--domain=foo", "--system-fqdn")

    @override_settings(
        INSTALLED_APPS=[
            app for app in settings.INSTALLED_APPS if app != "django.contrib.sites"
        ]
    )
    def test_should_raise_CommandError_Sites_framework_not_installed(self):
        with self.assertRaisesRegex(
            CommandError, "The sites framework is not installed."
        ):
            call_command("set_default_site", "--domain=foo", "--system-fqdn")

    @patch("sys.stdout", new_callable=StringIO)
    def test_should_print_Nothing_to_update(self, m_stdout):
        call_command("set_default_site")

        self.assertIn(
            "Nothing to update (need --name, --domain and/or --system-fqdn)\n",
            m_stdout.getvalue(),
        )

    @patch("django_extensions.management.commands.set_default_site.socket")
    def test_should_use_domain_as_name_if_system_fqdn_return_domain_and_name_is_not_provided(
        self, m_socket
    ):
        m_socket.getfqdn.return_value = "test.com"

        call_command("set_default_site", "--system-fqdn")
        result = Site.objects.get(pk=settings.SITE_ID)

        self.assertEqual(result.name, "test.com")
        self.assertEqual(result.domain, "test.com")

    @patch("django_extensions.management.commands.set_default_site.socket")
    def test_should_set_custom_nameif_system_fqdn_return_domain_and_name_is_provided(
        self, m_socket
    ):
        m_socket.getfqdn.return_value = "test.com"

        call_command("set_default_site", "--system-fqdn", "--name=foo")
        result = Site.objects.get(pk=settings.SITE_ID)

        self.assertEqual(result.name, "foo")
        self.assertEqual(result.domain, "test.com")

    def test_should_set_name_and_domain_if_provided(self):
        call_command("set_default_site", "--name=foo", "--domain=bar")
        result = Site.objects.get(pk=settings.SITE_ID)

        self.assertEqual(result.name, "foo")
        self.assertEqual(result.domain, "bar")

    def test_should_set_name_only(self):
        call_command("set_default_site", "--name=foo")
        result = Site.objects.get(pk=settings.SITE_ID)

        self.assertEqual(result.name, "foo")
        self.assertEqual(result.domain, "example.com")

    def test_should_set_domain_only(self):
        call_command("set_default_site", "--domain=bar")
        result = Site.objects.get(pk=settings.SITE_ID)

        self.assertEqual(result.name, "example.com")
        self.assertEqual(result.domain, "bar")

    def test_should_not_raise_if_sites_installed_through_appconfig(self):
        with self.modify_settings(
            INSTALLED_APPS={
                "append": "django.contrib.sites.apps.SitesConfig",
                "remove": "django.contrib.sites",
            }
        ):
            call_command("set_default_site", "--name=foo", "--domain=foo.bar")
